from datetime import datetime
from turbogears.database import PackageHub
from sqlobject import *
from turbogears import identity 

hub = PackageHub("onlineapidoc")
__connection__ = hub

soClasses = ('Visit',
             'VisitIdentity',
             'Group',
             'User',
             'Permission',
             'Space',
             'Template',
             'Page',
             'Page_History',
             'Comment')

#
# some constants and mappings to descriptive names
#

SPACE_STATUS_NOT_STARTED      = 1
SPACE_STATUS_ON_SCHEDULE      = 2
SPACE_STATUS_BEHIND_SCHEDULE  = 3
SPACE_STATUS_COMPLETE         = 4
SPACE_STATUS_UNAVAILABLE      = 5
space_status_codes            = { SPACE_STATUS_NOT_STARTED:     _('Not Started'),
                                SPACE_STATUS_ON_SCHEDULE:     _('On Schedule'), 
                                SPACE_STATUS_BEHIND_SCHEDULE: _('Behind Schedule'), 
                                SPACE_STATUS_COMPLETE:        _('Complete'),
                                SPACE_STATUS_UNAVAILABLE:        _('Unavailable')}


PAGE_TYPE_DIR = 1
PAGE_TYPE_LINK = 2
PAGE_TYPE_NORMAL_PAGE = 3
page_type_codes = { PAGE_TYPE_DIR: _('DIR'),
                   PAGE_TYPE_LINK: _('Link'),
                   PAGE_TYPE_NORMAL_PAGE: _('Page')}

LANG_CHN = 156
LANG_USA = 840
lang_codes = { LANG_CHN : _('Chinese'),
               LANG_USA : _('English')}

rls_encoding = ["utf-8", "gbk", "cp437"]

USDN_VER = 1.0

# identity models.
class Visit(SQLObject):
    class sqlmeta:
        table = "visit"

    visit_key = StringCol(length=40, alternateID=True, alternateMethodName="by_visit_key")
    created = DateTimeCol(default=datetime.now)
    expiry = DateTimeCol()

    def lookup_visit(cls, visit_key):
        try:
            return cls.by_visit_key(visit_key)
        except SQLObjectNotFound:
            return None
    lookup_visit = classmethod(lookup_visit)

class VisitIdentity(SQLObject):
    visit_key = StringCol(length=40, alternateID=True, alternateMethodName="by_visit_key")
    user_id = IntCol()


class Group(SQLObject):
    """
    An ultra-simple group definition.
    """

    # names like "Group", "Order" and "User" are reserved words in SQL
    # so we set the name to something safe for SQL
    class sqlmeta:
        table = "tg_group"

    group_name = UnicodeCol(length=16, alternateID=True, alternateMethodName="by_group_name")
    display_name = UnicodeCol(length=255)
    created = DateTimeCol(default=datetime.now)

    # collection of all users belonging to this group
    users = RelatedJoin("User", intermediateTable="user_group",
                        joinColumn="group_id", otherColumn="user_id")

    # collection of all permissions for this group
    permissions = RelatedJoin("Permission", joinColumn="group_id", 
                              intermediateTable="group_permission",
                              otherColumn="permission_id")


class User(SQLObject):
    """
    Reasonably basic User definition. Probably would want additional attributes.
    """
    # names like "Group", "Order" and "User" are reserved words in SQL
    # so we set the name to something safe for SQL
    class sqlmeta:
        table = "tg_user"

    user_name = UnicodeCol(length=16, alternateID=True, alternateMethodName="by_user_name")
    email_address = UnicodeCol(length=255, alternateID=True, alternateMethodName="by_email_address")
    display_name = UnicodeCol(length=255)
    password = UnicodeCol(length=40)
    created = DateTimeCol(default=datetime.now)

    # groups this user belongs to
    groups = RelatedJoin("Group", intermediateTable="user_group",
                         joinColumn="user_id", otherColumn="group_id")

    def _get_permissions(self):
        perms = set()
        for g in self.groups:
            perms = perms | set(g.permissions)
        return perms

    def _set_password(self, cleartext_password):
        "Runs cleartext_password through the hash algorithm before saving."
        password_hash = identity.encrypt_password(cleartext_password)
        self._SO_set_password(password_hash)

    def set_password_raw(self, password):
        "Saves the password as-is to the database."
        self._SO_set_password(password)



class Permission(SQLObject):
    permission_name = UnicodeCol(length=16, alternateID=True, alternateMethodName="by_permission_name")
    description = UnicodeCol(length=255)

    groups = RelatedJoin("Group",
                        intermediateTable="group_permission",
                         joinColumn="permission_id", 
                         otherColumn="group_id")


class Space(SQLObject):
    name = UnicodeCol(length=255, alternateID=True, alternateMethodName="by_space_name")
    description = UnicodeCol(length=255)
    archived = BoolCol(default=False)
    status = IntCol(default=SPACE_STATUS_NOT_STARTED)
    parent_space = ForeignKey('Space')
    admin = ForeignKey('User')
    sub_spaces = MultipleJoin('Space', joinColumn='parent_space_id')
    pages = MultipleJoin('Page', orderBy=['type', 'name'])
    language = IntCol(default=LANG_CHN)
    children_space = MultipleJoin('Space', joinColumn='parent_space_id')
    rls_encode = UnicodeCol(length=25, default='gbk')
    rls_default_page = ForeignKey('Page')
    
    def _get_root_pages(self):
        return [page for page in self.pages if not page.parent_page]
    
    def _get_root_normal_pages(self):
        return [page for page in self.pages if not page.parent_page and page.type == PAGE_TYPE_NORMAL_PAGE]
    
    def _get_all_normal_pages(self):
        return [page for page in self.pages if page.type == PAGE_TYPE_NORMAL_PAGE]

    def _get_all_dir_pages(self):
        return [page for page in self.pages if page.type == PAGE_TYPE_DIR]

    def _get_unbuilt_normal_pages(self):
        return [page for page in self.pages if page.type == PAGE_TYPE_NORMAL_PAGE and page.built == False]


class Template(SQLObject):
    name = UnicodeCol(length=255, alternateID=True, alternateMethodName="by_template_name")
    description = UnicodeCol(length=255)
    edit_template = UnicodeCol()
    view_template = UnicodeCol()
    author = ForeignKey('User')


class Page(SQLObject):
    name = UnicodeCol(length=255)
    content = UnicodeCol()
    space = ForeignKey('Space')
    parent_page = ForeignKey('Page')
    sub_pages = MultipleJoin('Page', joinColumn='parent_page_id', orderBy=['type', 'name'])
    type = IntCol(default=PAGE_TYPE_NORMAL_PAGE)
    built = BoolCol(default=False)
    comments = MultipleJoin('Comment')
    template = ForeignKey('Template')
    last_edit_user = ForeignKey('User')
    last_edit_time = DateTimeCol(default=datetime.now)
    version = IntCol()
    primary_copy = ForeignKey('Page')
    link_copies = MultipleJoin('Page', joinColumn='primary_copy_id')
    history_pages = MultipleJoin('Page_History', orderBy=["-version"])


class Page_History(SQLObject):
    page = ForeignKey('Page')
    version = IntCol()
    content = UnicodeCol()
    time = DateTimeCol(default=datetime.now)


class Comment(SQLObject):
    page = ForeignKey('Page')
    content = UnicodeCol()
    build_mark = BoolCol(default=False)
    author = ForeignKey('User')
    time = DateTimeCol(default=datetime.now)
